package com.example.opengldemo.util;

import android.opengl.Matrix;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

public class MatrixState {
    private static float[] mProjMatrix = new float[16];
    private static float[] mVMatrix = new float[16];
    private static float[] mMVPMatrix;
    static float[][] mStack = new float[10][16];
    static int stackTop = -1;
    private static float[] currMatrix;

    public static float[] setInitStack() {
        if(currMatrix == null){
            currMatrix = new float[16];
            Matrix.setRotateM(currMatrix, 0, 0, 1, 0, 0);
        }
        return currMatrix ;
    }
    public static float[] pushMatrix() {
        stackTop++;
        for (int i = 0; i < 16; i++) {
            mStack[stackTop][i] = currMatrix[i];
        }
        return currMatrix ;
    }
    public static float[] popMatrix() {
        for (int i = 0; i < 16; i++) {
            currMatrix[i] = mStack[stackTop][i];
        }
        stackTop--;
        return currMatrix ;
    }
    private static float[] mVMatrixForSpecFrame = new float[16];
    public static void copyMVMatrix()
    {
        for(int i=0;i<16;i++)
        {
            mVMatrixForSpecFrame[i]=mVMatrix[i];
        }
    }
    public static void matrix(float[] self)
    {
        float[] result=new float[16];
        Matrix.multiplyMM(result,0,currMatrix,0,self,0);
        currMatrix=result;
    }

    // 矩阵平移
    public static float[]  translate = new float[3] ;
    public static void translate(float x, float y, float z) {
        translate(currMatrix, x, y, z);
    }
    public static void translate(float[] matrix , float x, float y, float z) {
        Matrix.translateM(matrix, 0, x, y, z);
    }

    // 矩阵旋转
    public static float[]  rotate = new float[3] ;
    public static void rotate(float angle, float x, float y, float z) {
        rotate(currMatrix,  angle, x, y, z);
    }
    public static void rotate(float[] matrix  , float angle, float x, float y, float z) {
        Matrix.rotateM(matrix, 0, angle, x, y, z);
    }

    // 矩阵缩放
    public static float[]  scale = new float[3] ;
    public static void scale(float x, float y, float z) {
        scale(currMatrix,  x, y, z);
    }
    public static void scale(float[] matrix  , float x, float y, float z) {
        Matrix.scaleM(matrix, 0, x, y, z);
    }

    public static float[] getMMatrix() {
        return currMatrix;
    }


    // 投影矩阵
    public static float[] projectLocation = new float[6] ;
    public static void setProjectOrtho(
            float left, float right,
            float bottom, float top,
            float near, float far
    ) {
        setProjectOrtho (mProjMatrix, 0, left, right, bottom, top, near, far);
    }

    public static void setProjectOrtho(
            float[] matrix , int offset ,
            float left, float right,
            float bottom, float top,
            float near, float far
    ) {
        Matrix.orthoM(matrix, offset, left, right, bottom, top, near, far);
    }


    public static void setProjectFrustum(
            float left, float right,
            float bottom, float top,
            float near, float far
    ) {
        setProjectFrustum(mProjMatrix, 0, left, right, bottom, top, near, far);
    }

    public static void setProjectFrustum(
            float[] matrix , int offset ,
            float left, float right,
            float bottom, float top,
            float near, float far
    ) {
        Matrix.frustumM(matrix, offset, left, right, bottom, top, near, far);
    }



    //摄像机位置
    public static float[] cameraLocation = new float[]{0, 0, 0};
    public static FloatBuffer cameraLocationFB;
    public static void setCamera(
            float cx, float cy, float cz,
            float tx, float ty, float tz,
            float upx, float upy, float upz
    ) {
        llbbL.clear();
        setCamera(mVMatrix, 0, cx, cy, cz, tx, ty, tz, upx, upy, upz);
        cameraLocation[0] = cx;
        cameraLocation[1] = cy;
        cameraLocation[2] = cz;
        cameraLocationFB = llbbL.order(ByteOrder.nativeOrder()).asFloatBuffer();
        cameraLocationFB.put(cameraLocation).position(0);
    }
    public static void setCamera(
            float[] floats , int offset ,
            float cx, float cy, float cz,
            float tx, float ty, float tz,
            float upx, float upy, float upz
    ) {
        Matrix.setLookAtM(floats, offset, cx, cy, cz, tx, ty, tz, upx, upy, upz);
    }
    public static float[] getInvertMvMatrix(){
        float[] invM = new float[16];
        Matrix.invertM(invM, 0, mVMatrix, 0);
        return invM;
    }
     public static float[] fromPtoPreP(float[] p){
         float[] inverM = getInvertMvMatrix();
        float[] preP = new float[4];
        Matrix.multiplyMV(preP, 0, inverM, 0, new float[]{p[0],p[1],p[2],1}, 0);
        return new float[]{preP[0],preP[1],preP[2]};
    }
    //光源位置 平行光
    static ByteBuffer llbbL = ByteBuffer.allocateDirect(3 * 4);
    public static float[] lightLocation = new float[]{0, 0, 0};
    public static FloatBuffer lightLocationFB;
    public static void setLightLocation(float x, float y, float z) {
        llbbL.clear();
        lightLocation[0] = x;
        lightLocation[1] = y;
        lightLocation[2] = z;
        lightLocationFB = llbbL.order(ByteOrder.nativeOrder()).asFloatBuffer();
        lightLocationFB.put(lightLocation).position(0);
    }

    //光源位置 点光
    public static float[] lightDirection = new float[]{0, 0, 1};
    public static FloatBuffer lightDirectionFB;
    public static void setLightDirection(float x, float y, float z) {
        llbbL.clear();
        lightDirection[0] = x;
        lightDirection[1] = y;
        lightDirection[2] = z;
        llbbL.order(ByteOrder.nativeOrder());
        lightDirectionFB = llbbL.asFloatBuffer();
        lightDirectionFB.put(lightDirection);
        lightDirectionFB.position(0);
    }


    //最终矩阵
    public static float[] getFinalMatrix() {
        return getFinalMatrix(currMatrix);
    }

    public static float[] getFinalMatrix(float[] spec) {
        mMVPMatrix = getFinalMatrix(spec , mVMatrix , mProjMatrix) ;
        return mMVPMatrix ;
    }
    public static float[] getFinalMatrix(float[] spec , float[] VMatrix) {
        float[] mMVPMatrix = new float[16];
        Matrix.multiplyMM(mMVPMatrix, 0, VMatrix, 0, spec, 0);
        return mMVPMatrix;
    }
    public static float[] getFinalMatrix(float[] spec , float[] VMatrix , float[] project ) {
        float[] mMVPMatrix = new float[16];
        Matrix.multiplyMM(mMVPMatrix, 0, VMatrix, 0, spec, 0);
        Matrix.multiplyMM(mMVPMatrix, 0, project, 0, mMVPMatrix, 0);
        return mMVPMatrix;
    }

}
